package vip.xls8z.learning.nio.reactor.single;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

@Slf4j
public class Handler implements Runnable {
    final Selector selector;
    final SocketChannel socketChannel;
    SelectionKey selectionKey;

    ByteBuffer inputBuff = ByteBuffer.allocate(1024);
    ByteBuffer outputBuff = ByteBuffer.allocate(1024);

    public Handler(Selector selector, SocketChannel socketChannel) throws ClosedChannelException {
        this.selector = selector;
        this.socketChannel = socketChannel;

        selectionKey = socketChannel.register(selector, SelectionKey.OP_READ);
        selectionKey.attach(this);
        selector.wakeup();
    }

    @Override
    public void run() {
        try {
            if (selectionKey.isReadable()) {
                read();
            }

            if (selectionKey.isWritable()) {
                send();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void send() throws IOException {
        outputBuff.clear();
        String message = "Hello, Client. " + UUID.randomUUID();
        outputBuff.put(message.getBytes(StandardCharsets.UTF_8));
        outputBuff.flip();
        socketChannel.write(outputBuff);
        log.info("write message: {}", message);

        selectionKey.interestOps(SelectionKey.OP_READ);
        selectionKey.selector().wakeup();
    }

    private void read() throws IOException {
        inputBuff.clear();
        int length = socketChannel.read(inputBuff);
        if (length == -1) {
            socketChannel.close();
            selectionKey.cancel();
            return;
        }

        inputBuff.flip();
        String message = new String(inputBuff.array(), 0, length);
        log.info("read message: {}", message);

        selectionKey.interestOps(SelectionKey.OP_WRITE);
        selectionKey.selector().wakeup();
    }
}
